/**
  ******************************************************************************
  * @file    message_queue.c
  * @author  ashuai0110
  * @version V2.1
  * @date    2023-09-20
  * @brief   消息队列
  *          (适合不定长数据和复杂数据,写入时动态申请内存)
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "message_queue.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup message_queue message_queue
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup message_queue_local_macros message_queue local macros
 * @{
 */

/**
 * @defgroup message_queue_check_parameters_validity message_queue check parameters validity
 * @{
 */
/* 消息队列数据大小有效性检查 */
#define IS_VALID_QA_SIZE(x)                                                   \
(       (x) != 0u)
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup message_queue_global_functions message_queue global functions
 * @{
 */

/**
  * @brief  消息队列初始化
  *
  * @param  _mq  : 消息队列实例
  *
  * @param  size : 消息队列消息数量
  *
  * @retval None
  */
void mes_queue_init(mes_queue_t *_mq, uint32_t size)
{
    ASSERT_PARAM(IS_VALID_POINT(_mq));
    ASSERT_PARAM(IS_VALID_QA_SIZE(size));

    _mq->pHead = _mq->pTail = NULL;
    _mq->maxCnt = size;
    _mq->curCnt = 0;
}

/**
  * @brief  消息队列删除
  *
  * @note   将消息队列内所有消息占用内存释放
  *
  * @param  _mq : 消息队列实例
  *
  * @retval None
  */
void mes_queue_delete(mes_queue_t *_mq)
{
    ASSERT_PARAM(IS_VALID_POINT(_mq));

    while(_mq->pHead != NULL)
    {
        _mq->pTail = _mq->pHead;
        _mq->pHead = _mq->pHead->pNext;
        MQ_FREE(_mq->pTail);
    }
    memset(_mq, 0, sizeof(mes_queue_t));
}

/**
  * @brief  向消息队列写入数据
  *
  * @param  _mq     : 消息队列实例
  *
  * @param  pData   : 写入的数据
  *
  * @param  size    : 写入的数据大小byte
  *
  * @retval uint8_t
  *    @arg RET_OK  : 成功
  *    @arg RET_ERR : 消息队列已满(不可写)
  */
uint8_t mes_queue_write(mes_queue_t *_mq, void *pData, uint32_t size)
{
    ASSERT_PARAM(IS_VALID_POINT(_mq));
    ASSERT_PARAM(IS_VALID_POINT(pData));
    ASSERT_PARAM(IS_VALID_QA_SIZE(size));

    if(_mq->curCnt >= _mq->maxCnt) { return RET_ERR; }

    if(NULL == _mq->pHead)
    {
        _mq->pHead = (mes_queue_item_t *)MQ_MALLOC(sizeof(mes_queue_item_t) + size);
        _mq->pTail = _mq->pHead;
    }
    else
    {
        _mq->pTail->pNext = (mes_queue_item_t *)MQ_MALLOC(sizeof(mes_queue_item_t) + size);
        _mq->pTail = _mq->pTail->pNext;
    }
    _mq->pTail->pNext = NULL;
    _mq->pTail->size = size;
    memcpy(_mq->pTail->data, pData, size);
    _mq->curCnt = _mq->curCnt + 1;

    return RET_OK;
}

/**
  * @brief  从消息队列读出数据
  *
  * @param  _mq     : 消息队列实例
  *
  * @param  pBuf    : 读出的数据
  *
  * @param  size    : 读出的数据大小byte
  *
  * @retval uint8_t
  *    @arg RET_OK  : 成功
  *    @arg RET_ERR : 消息队列为空(不可读)
  */
uint8_t mes_queue_read(mes_queue_t *_mq, void *pBuf, uint32_t *size)
{
    mes_queue_item_t *pTmp;

    ASSERT_PARAM(IS_VALID_POINT(_mq));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    ASSERT_PARAM(IS_VALID_POINT(size));
    
    if(NULL == _mq->pHead || 0 == _mq->curCnt) { return RET_ERR; }
    
    pTmp = _mq->pHead;
    *size = _mq->pHead->size;
    memcpy(pBuf, (void *)_mq->pHead->data, _mq->pHead->size);
    _mq->pHead = _mq->pHead->pNext;
    if(_mq->pHead == NULL) { _mq->pTail = NULL; }
    MQ_FREE(pTmp);
    _mq->curCnt = _mq->curCnt - 1;

    return RET_OK;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
